import 'package:flutter/material.dart';
import 'package:flutter_provider_demo/commons/command.dart';
import 'package:flutter_provider_demo/commons/result.dart';
import 'package:flutter_provider_demo/data/models/cart.dart';
import 'package:flutter_provider_demo/data/models/catalog.dart';
import 'package:flutter_provider_demo/data/repositories/cart_repository.dart';
import 'package:flutter_provider_demo/data/repositories/catalog_repository.dart';

class CatalogViewmodel extends ChangeNotifier {
  CatalogViewmodel({
    required CatalogRepository catalogRepository,
    required CartRepository cartRepository,
  })  : _catalogRepository = catalogRepository,
        _cartRepository = cartRepository {
    loadCatalog = Command0(_loadCatalog);
    loadMoreCatalog = Command0(_loadMoreCatalog);
    loadCarts = Command0(_loadCarts)..execute();
    addToCart = Command1<void, CatalogModel>(_addToCart);
    removeFromCart = Command1<void, int>(_removeFromCart);
  }
  final CatalogRepository _catalogRepository;
  final CartRepository _cartRepository;
  int _page = 1;
  bool _hasMore = true;
  final ValueNotifier<List<CatalogModel>> _catalog = ValueNotifier([]);
  final ValueNotifier<Set<int>> _cartCatalogIds = ValueNotifier({});

  late Command0 loadCatalog;
  late Command0 loadMoreCatalog;
  late Command1 addToCart;
  late Command1 removeFromCart;
  late Command0 loadCarts;

  ValueNotifier<List<CatalogModel>> get catalog => _catalog;
  ValueNotifier<Set<int>> get cartCatalogIds => _cartCatalogIds;

  void init() async {
    await Future.delayed(const Duration(seconds: 1));
  }

  Future<Result<void>> _loadCatalog() async {
    await Future.delayed(const Duration(seconds: 1));
    _page = 1;
    Result<List<CatalogModel>> result = await _catalogRepository.getCatalog(_page);
    if (result is Ok) {
      _catalog.value = (result as Ok).value;
    }
    return result;
  }

  Future<Result<void>> _loadMoreCatalog() async {
    if (!_hasMore) {
      return Result.ok(null);
    }
    await Future.delayed(const Duration(seconds: 1));
    _page++;
    Result<List<CatalogModel>> result = await _catalogRepository.getCatalog(_page);
    if (result is Ok) {
      final catalogs = (result as Ok).value;
      if (catalogs.isNotEmpty) {
        _catalog.value = [..._catalog.value, ...(result as Ok).value];
      } else {
        _hasMore = false;
      }
    }
    return result;
  }

  Future<Result<void>> _loadCarts() async {
    List<CartModel> carts = await _cartRepository.getAll();
    if (carts.isNotEmpty) {
      _cartCatalogIds.value = carts.map((item) => item.catalogId).toSet();
    }
    return Result.ok(null);
  }

  Future<Result<void>> _addToCart(CatalogModel catalog) async {
    _cartCatalogIds.value = {..._cartCatalogIds.value, catalog.id};
    await _cartRepository.add(CartModel(
      catalogId: catalog.id,
      catalogName: catalog.name,
      price: catalog.price,
    ));
    return Result.ok(null);
  }

  Future<Result<void>> _removeFromCart(int catalogId) async {
    _cartCatalogIds.value = _cartCatalogIds.value.where((e) => e != catalogId).toSet();
    CartModel? cart = await _cartRepository.getByCatalogId(catalogId);
    if (cart != null) {
      await _cartRepository.deleteByCatalogId(catalogId);
    }
    return Result.ok(null);
  }
}
